#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <cstring>

using namespace std;

// 配置串口的函数
void configureSerialPort(int fd, int baudRate, int dataBits, int stopBits, char parity) {
    struct termios options;

    // 获取当前串口的设置
    if (tcgetattr(fd, &options) < 0) {
        cerr << "Error getting serial port attributes" << endl;
        return;
    }

    // 设置波特率
    cfsetispeed(&options, baudRate);
    cfsetospeed(&options, baudRate);

    // 设置数据位（通常为 8 位）
    options.c_cflag &= ~CSIZE;  // 清除数据位设置
    switch (dataBits) {
        case 5: options.c_cflag |= CS5; break;
        case 6: options.c_cflag |= CS6; break;
        case 7: options.c_cflag |= CS7; break;
        case 8: options.c_cflag |= CS8; break;
        default:
            cerr << "Invalid data bits" << endl;
            return;
    }

    // 设置停止位
    if (stopBits == 1) {
        options.c_cflag &= ~CSTOPB;  // 1 位停止位
    } else if (stopBits == 2) {
        options.c_cflag |= CSTOPB;   // 2 位停止位
    } else {
        cerr << "Invalid stop bits" << endl;
        return;
    }

    // 设置校验位
    if (parity == 'N') {
        options.c_cflag &= ~PARENB;  // 无校验
        options.c_iflag &= ~INPCK;   // 不启用输入校验
    } else if (parity == 'O') {
        options.c_cflag |= PARENB;   // 开启校验
        options.c_cflag |= PARODD;   // 奇校验
        options.c_iflag |= INPCK;    // 启用输入校验
    } else if (parity == 'E') {
        options.c_cflag |= PARENB;   // 开启校验
        options.c_cflag &= ~PARODD;  // 偶校验
        options.c_iflag |= INPCK;    // 启用输入校验
    } else {
        cerr << "Invalid parity option" << endl;
        return;
    }

    // 使能串口配置并关闭硬件流控制
    options.c_cflag |= (CLOCAL | CREAD);  // 启用接收并忽略调制解调器控制线
    options.c_cflag &= ~CRTSCTS;          // 禁用硬件流控制

    // 设置串口为原始模式
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // 设置数据传输时的字符大小，接收超时等
    options.c_cc[VMIN] = 1;    // 至少读取 1 字节数据
    options.c_cc[VTIME] = 5;   // 超时 0.5 秒

    // 应用配置
    if (tcsetattr(fd, TCSANOW, &options) < 0) {
        cerr << "Error setting serial port attributes" << endl;
        return;
    }
}

// 读取串口数据
void readFromSerial(int fd) {
    char buf[256];
    int n = read(fd, buf, sizeof(buf) - 1);
    if (n < 0) {
        cerr << "Read error" << endl;
        return;
    }
    buf[n] = '\0';
    cout << "Received data: " << buf << endl;
}

// 写入串口数据
void writeToSerial(int fd, const char* data) {
    int len = strlen(data);
    int n = write(fd, data, len);
    if (n < 0) {
        cerr << "Write error" << endl;
        return;
    }
    cout << "Sent data: " << data << endl;
}

int main() {
    // 打开串口设备
    const char* device = "/dev/ttyS0";  // 这里使用的是 /dev/ttyS0，可以根据实际情况修改
    int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1) {
        cerr << "Failed to open serial port " << device << endl;
        return -1;
    }

    // 配置串口：波特率为 9600，数据位 8，停止位 1，无校验
    configureSerialPort(fd, B9600, 8, 1, 'N');

    // 向 STM32 发送数据
    const char* dataToSend = "Hello STM32!";
    writeToSerial(fd, dataToSend);

    // 从 STM32 读取数据
    readFromSerial(fd);

    // 关闭串口
    close(fd);

    return 0;
}